package com.fishingwithme.controllers;

import com.fishingwithme.domain.CityService;
import com.fishingwithme.domain.anybiting.MessageType;
import com.fishingwithme.domain.anybiting.SubType;
import com.fishingwithme.domain.circle.CircleGeoService;
import com.fishingwithme.domain.circle.CircleRedisMessagePublisher;
import com.fishingwithme.domain.circle.CircleService;
import com.fishingwithme.domain.common.Location;
import cn.fishingwithme.infrastructure.dtos.*;
import cn.fishingwithme.infrastructure.dtos.circle.*;
import com.fishingwithme.infrastructure.dtos.DTO;
import com.fishingwithme.infrastructure.dtos.anybiting.BaseCircleMessageDto;
import com.fishingwithme.infrastructure.dtos.circle.*;
import com.fishingwithme.infrastructure.utils.CommonUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

import static com.fishingwithme.infrastructure.cfg.RedisConfig.CIRCLE_MESSAGE_CHANNEL;
import static com.fishingwithme.infrastructure.utils.CommonUtils.now;

@Controller
@RequestMapping("/circle")
@Tag(name = "Circle Management", description = "APIs for managing fishing circles and related operations")
public class CircleController {
    private static final Logger logger = LoggerFactory.getLogger(CircleController.class);

    @Autowired
    private CircleService circleService;
    @Autowired
    private CircleRedisMessagePublisher circleRedisMessagePublisher;
    @Autowired
    private CircleGeoService circleGeoService;
    @Autowired
    private CityService cityService;

    @RequestMapping(path = "/getCity")
    @Operation(
            summary = "Get city information by coordinates",
            description = "Get city information based on latitude and longitude coordinates"
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "City information retrieved successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            )
    })
    public @ResponseBody DTO<CityDto> getCity(
            @Parameter(description = "Latitude coordinate", required = true, example = "39.9042")
            @RequestParam Double latitude,
            @Parameter(description = "Longitude coordinate", required = true, example = "116.4074")
            @RequestParam Double longitude) {
        return DTO.success(circleService.getCity(latitude,longitude));
    }

    @RequestMapping(path = "/delete")
    public @ResponseBody DTO<Boolean> delete(@RequestParam("id") Long circleId) {
        Boolean status = circleService.deleteCircle(circleId);
        return status ? DTO.success(Boolean.TRUE) : DTO.fail(Boolean.FALSE, "删除失败");

    }

    @RequestMapping(path = "/markActive")
    public @ResponseBody DTO<Boolean> markCircle(@RequestParam("id") Long circleId, @RequestParam(defaultValue = "1") Boolean isActive) {
        Boolean status = circleService.markActive(circleId, isActive);
        return status ? DTO.success(Boolean.TRUE) : DTO.fail(Boolean.FALSE, "启用失败");

    }

    @RequestMapping(path = "/getCircles")
    @Operation(
            summary = "Get circles by location",
            description = "Retrieve circles within a specific location radius"
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Circles retrieved successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            )
    })
    public @ResponseBody DTO<List<CircleDto>> getCircleByLocation(
            @Parameter(description = "Location coordinates", required = true)
            @RequestBody Location location) {
        return DTO.success(circleService.getCircles(location, CommonUtils.DEFAULT_CIRCLE_DISTANCE));
    }


    @RequestMapping(path = "/list")
    public @ResponseBody IPage<CirclePageDto> list(
            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
        return circleService.listPage(pageNum, pageSize);

    }

    @RequestMapping(path = "/add")
    @Operation(
            summary = "Create new circle",
            description = "Create a new fishing circle",
            security = @SecurityRequirement(name = "Bearer Authentication")
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Circle created successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "Invalid circle data",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            ),
            @ApiResponse(
                    responseCode = "401",
                    description = "Unauthorized - JWT token required"
            )
    })
    public @ResponseBody DTO<Boolean> createCircle(
            @Parameter(description = "Circle information", required = true)
            @RequestBody CircleDto circle) {
        CircleDto.format(circle);
        Boolean status = circleService.add(circle);
        return status ? DTO.success(Boolean.TRUE) : DTO.fail(Boolean.FALSE, "添加失败");
    }

    /// TODO:
    @PostMapping(path = "/message")
    public @ResponseBody DTO<Boolean> sendCircleMessage(@RequestBody CircleAskMessageDto dto) {
        Long userId = CommonUtils.getUserId();
        dto.setUserId(userId);
        BaseCircleMessageDto baseCircleMessageDto = new BaseCircleMessageDto();
        baseCircleMessageDto.setContent(dto);
        //baseCircleMessageDto.setCity(dto.getCity());
        baseCircleMessageDto.setSubtype(SubType.EVT_ASK);
        baseCircleMessageDto.setSender("system");
        baseCircleMessageDto.setTimestamp(now());
        baseCircleMessageDto.setType(MessageType.EVT);
        circleRedisMessagePublisher.publish(CIRCLE_MESSAGE_CHANNEL, baseCircleMessageDto);
        return DTO.success(Boolean.TRUE);

    }

    @GetMapping(path = "/getCircleLocations")
    public @ResponseBody DTO<List<CircleLocationDto>> getCircleLocations(@RequestParam Double latitude, @RequestParam Double longitude) {
        return DTO.success(circleService.getCircleLocations(latitude, longitude, CommonUtils.DEFAULT_CIRCLE_DISTANCE));
    }

    @GetMapping(path = "/spot/search")
    public @ResponseBody DTO<List<CircleSpotDto>> queryCircleSpots(Long circleId, String queryStr) {
        return DTO.success(circleService.queryCircleSpots(circleId, queryStr));
    }

    @GetMapping(path = "/get")
    public @ResponseBody DTO<CircleDetailDto> get(@RequestParam("id") Long id) {
        CircleDetailDto detail = circleService.get(id);
        return detail != null ? DTO.success(detail) : DTO.fail(null, "圈子不存在");
    }

    @PostMapping(path = "/update")
    public @ResponseBody DTO<Boolean> update(@RequestBody CircleUpdateDto updateDto) {
        Boolean status = circleService.updateCircle(updateDto);
        return status ? DTO.success(Boolean.TRUE) : DTO.fail(Boolean.FALSE, "更新失败");
    }

    @GetMapping(path = "/match")
    public @ResponseBody DTO<List<SpotInCircleDto>> getSpotsInCircle(@RequestParam("id") Long id) {
        List<SpotInCircleDto> spots = circleGeoService.getSpotsInCircle(id);
        return DTO.success(spots);
    }
    
    @PostMapping(path="/save_match")
    public @ResponseBody DTO<Integer> saveMatch(@RequestBody SaveMatchDto saveMatchDto) {
        try {
            if (saveMatchDto.getId() == null || saveMatchDto.getSpotIds() == null || saveMatchDto.getSpotIds().isEmpty()) {
                return DTO.fail(0, "参数不能为空");
            }
            
            // 验证圈子是否存在
            CircleDetailDto circle = circleService.get(saveMatchDto.getId());
            if (circle == null) {
                return DTO.fail(0, "圈子不存在");
            }
            
            // 通过Service层调用
            Integer successCount = circleService.batchAddSpotsToCircle(saveMatchDto.getId(), saveMatchDto.getSpotIds());
            return DTO.success(successCount);
            
        } catch (Exception e) {
            logger.error("保存圈子spot关联失败", e);
            return DTO.fail(0, "操作失败: " + e.getMessage());
        }
    }
    
    @GetMapping(path = "/spots")
    public @ResponseBody IPage<SpotInCircleDto> getCircleSpots(
            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(required = false, defaultValue = "10") Integer pageSize,
            @RequestParam Long id) {
        return circleService.getCircleSpotsPage(pageNum, pageSize, id);
    }
    
    @GetMapping(path = "/getCities")
    public @ResponseBody DTO<List<CityDto>> getCities() {
        List<CityDto> cities = cityService.getAllCities();
        return DTO.success(cities);
    }
    
    @GetMapping(path = "/searchCities")
    public @ResponseBody DTO<List<CityDto>> searchCities(@RequestParam String keyword) {
        List<CityDto> cities = cityService.searchCities(keyword);
        return DTO.success(cities);
    }
    
    @GetMapping(path = "/refreshCities")
    @Operation(
            summary = "Refresh city data from spots",
            description = "Trigger manual refresh of city data by aggregating information from spot table"
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "City data refresh triggered successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            )
    })
    public @ResponseBody DTO<Boolean> refreshCities() {
        cityService.refreshCityData();
        return DTO.success(Boolean.TRUE);
    }
    
    @GetMapping(path = "/cities/page")
    @Operation(
            summary = "Get cities by page",
            description = "Retrieve city list with pagination, default limit is 50. Support searching by city name."
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "City list retrieved successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            )
    })
    public @ResponseBody DTO<IPage<CityDto>> getCitiesByPage(
            @Parameter(description = "Page number, default is 1", example = "1")
            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
            @Parameter(description = "Page size, default is 50", example = "50")
            @RequestParam(required = false, defaultValue = "50") Integer pageSize,
            @Parameter(description = "City name search keyword", example = "Beijing")
            @RequestParam(required = false) String city) {
        IPage<CityDto> pageResult = cityService.getCitiesByPageAndSearch(pageNum, pageSize, city);
        return DTO.success(pageResult);
    }
    
    @PostMapping(path = "/cities/add")
    @Operation(
            summary = "Add a new city",
            description = "Create a new city with city code and city name"
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "City added successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "Invalid city data",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DTO.class)
                    )
            )
    })
    public @ResponseBody DTO<Boolean> addCity(
            @Parameter(description = "City information", required = true)
            @RequestBody CityDto cityDto) {
        boolean result = cityService.addCity(cityDto);
        return result ? DTO.success(Boolean.TRUE) : DTO.fail(Boolean.FALSE, "添加失败");
    }
}
